<?php
require_once('simpletest/autorun.php');
require_once('../templar.php');
require_once('templar_testing_resources.php');


/**********************************************************************
 * Test of successful TemplarTemplateEngine instantiation.
 *********************************************************************/
class TestInstantiation extends UnitTestCase {
    function testInstantiateMainClass() {
        $templar = &new MockTemplarPHP();
        $template = new TemplarTemplateEngine($templar);
        $this->assertNotNull($template);
    }
}

/**********************************************************************
 *
 *********************************************************************/
class TestProxyInstantiation extends TemplateUnitTestCase {
    function testInitialProperties() {
        $template = $this->template;
        $this->assertNotNull($template);

        $this->assertEqual($template->sandboxLabel, 'content');

        $pos = strpos($template->processingTarget, $template->manglingToken);
        $this->assertEqual($pos, strlen('templar')); // ends with mangiling token?
    }
}

class TestAssignValues extends TemplateUnitTestCase {
    function testBuiltInVars() {
        $dom = new DOMDocument();
        $markup = <<<MARKUP
<html>
    <head>
        <title>Hello Title</title>
    </head>
    <body>
        <h1>Hello Body</h1>
    </body>
</html>
MARKUP;
        $dom->loadHTML($markup);
        $template = $this->template;
        $template->assignValues($dom);

        $title = $template->varNodes['title'];
        $this->assertIsA($title, 'DOMElement');
        $this->assertEqual($title->tagName, 'title');
        $this->assertEqual($title->nodeValue, 'Hello Title');

        $body = $template->varNodes['body'];
        $this->assertIsA($body, 'DOMElement');
        $this->assertEqual($body->tagName, 'body');
        $this->assertPattern('/Hello Body/', $body->nodeValue);

        $this->assertEqual(count($template->varNodes), 2);
    }
    function testIdVars() {
        $dom = new DOMDocument();
        $markup = <<<MARKUP
<html>
    <head>
        <title>Hello Title</title>
    </head>
    <body>
        <h1>Hello Body</h1>
        <p id="test_var">Hello ID</p>
    </body>
</html>
MARKUP;
        $dom->loadHTML($markup);
        $template = $this->template;
        $template->assignValues($dom);

        $title = $template->varNodes['test_var'];
        $this->assertIsA($title, 'DOMElement');
        $this->assertEqual($title->tagName, 'p');
        $this->assertEqual($title->nodeValue, 'Hello ID');

        $this->assertEqual(count($template->varNodes), 3);
    }
}

/**********************************************************************
 *
 *********************************************************************/
class TestGetAllIdElements extends TemplateUnitTestCase {
    function testBasics() {
        $dom = new DOMDocument();
        $markup = <<<MARKUP
<html>
    <head>
        <title>Hello Title</title>
    </head>
    <body>
        <h1>Hello Body</h1>
        <p id="para_1">Paragraph One</p>
        <p id="para_2">Paragraph Two</p>
        <p id="para_3">Paragraph Three</p>
    </body>
</html>
MARKUP;
        $dom->loadHTML($markup);
        $id_elements = $this->template->getAllIdElements($dom);
        $this->assertEqual(count($id_elements), 3);
    }
}

/**********************************************************************
 *
 *********************************************************************/
class TestFollowingNode extends TemplateUnitTestCase {
    function testStepThroughNodeTree() {
        $dom = new DOMDocument();
        $markup = <<<MARKUP
<html>
    <head>
        <title>Hello Title</title>
    </head>
    <body><h1>Hello Body</h1></body>
</html>
MARKUP;
        $dom->loadHTML($markup);
        $template = $this->template;

        $node = $dom->documentElement;
        $this->assertEqual($node->nodeType, XML_ELEMENT_NODE);
        $this->assertEqual($node->tagName, 'html');

        $node = $template->followingNode($node);
        $this->assertEqual($node->nodeType, XML_ELEMENT_NODE);
        $this->assertEqual($node->tagName, 'head');

        $node = $template->followingNode($node);
        $this->assertEqual($node->nodeType, XML_ELEMENT_NODE);
        $this->assertEqual($node->tagName, 'title');

        $node = $template->followingNode($node);
        $this->assertEqual($node->nodeType, XML_TEXT_NODE);
        $this->assertEqual($node->nodeValue, 'Hello Title');

        $node = $template->followingNode($node);
        $this->assertEqual($node->nodeType, XML_ELEMENT_NODE);
        $this->assertEqual($node->tagName, 'body');

        $node = $template->followingNode($node);
        $this->assertEqual($node->nodeType, XML_ELEMENT_NODE);
        $this->assertEqual($node->tagName, 'h1');

        $node = $template->followingNode($node);
        $this->assertEqual($node->nodeType, XML_TEXT_NODE);
        $this->assertEqual($node->nodeValue, 'Hello Body');

        $node = $template->followingNode($node);
        $this->assertNull($node);
    }

    function testCommonStartingPoints() {
        $dom = new DOMDocument();
        $markup = <<<MARKUP
<html>
    <head>
        <title>Test</title>
    </head>
    <body><h1>Test</h1></body>
</html>
MARKUP;
        $dom->loadHTML($markup);
        $template = $this->template;

        /* test starting with DOMDocument as arg */
        $node = $template->followingNode($dom);
        $this->assertEqual($node->nodeType, XML_DOCUMENT_TYPE_NODE);
        $node = $template->followingNode($node); // step to next node
        $this->assertEqual($node->nodeType, XML_ELEMENT_NODE);
        $this->assertEqual($node->tagName, 'html');
        $node = $template->followingNode($node); // step to next node
        $this->assertEqual($node->nodeType, XML_ELEMENT_NODE);
        $this->assertEqual($node->tagName, 'head');

        /* test starting with documentElement ('html' node) as arg */
        $node = $template->followingNode($dom->documentElement);
        $this->assertEqual($node->nodeType, XML_ELEMENT_NODE);
        $this->assertEqual($node->tagName, 'head');
    }
}

/**********************************************************************
 *
 *********************************************************************/
class TestIsMangled extends TemplateUnitTestCase {
    function testBasicIsMangled() {
        $template = $this->template;
        $template->manglingToken = '_dummytoken';

        $is_mangled = $template->isMangled('foo_dummytoken');
        $this->assertTrue($is_mangled);

        $is_mangled = $template->isMangled('bar');
        $this->assertFalse($is_mangled);
    }
}

/**********************************************************************
 *
 *********************************************************************/
class TestMangle extends TemplateUnitTestCase {
    function testBasicMangling() {
        $template = $this->template;
        $template->manglingToken = '_v7jzkv';

        $mangled = $template->mangle('blue');
        $this->assertEqual($mangled, 'blue_v7jzkv');

        $mangled = $template->mangle('red');
        $mangled = $template->mangle($mangled);
        $this->assertEqual($mangled, 'red_v7jzkv', "Double-mangling should have no effect.");
    }
}

/**********************************************************************
 *
 *********************************************************************/
class TestUnmangle extends TemplateUnitTestCase {
    function testBasicUnmangling() {
        $template = $this->template;
        $template->manglingToken = '_6sv29q';

        $unmangled = $template->unmangle('blue_6sv29q');
        $this->assertEqual($unmangled, 'blue');

        $unmangled = $template->unmangle('red');
        $this->assertEqual($unmangled, 'red');

        // In operating code, there's less than a one in 2 billion
        // chance of intentional collision using a faux token.
    }
}

/**********************************************************************
 *
 *********************************************************************/
class TestNodeByTagName extends TemplateUnitTestCase {
    function testBasicNodeByTagName() {
        $dom = new DOMDocument();
        $markup = <<<MARKUP
<html>
    <head>
        <title>Test</title>
    </head>
    <body>
        <H1>Test</H1>
        <p>First Paragraph</p>
        <p>Second Paragraph</p>
    </body>
</html>
MARKUP;
        $dom->loadHTML($markup);
        $template = $this->template;

        $node = $template->nodeByTagName($dom, 'title');
        $this->assertIsA($node, 'DOMElement');

        $node = $template->nodeByTagName($dom, 'p');
        $this->assertIsA($node, 'DOMElement');
        $this->assertEqual($node->nodeValue, 'First Paragraph', "Should return first node only.");

        $node = $template->nodeByTagName($dom, 'h1');
        $this->assertIsA($node, 'DOMElement', "Should check for capitalized version.");

        $node = $template->nodeByTagName($dom, 'table');
        $this->assertNull($node);
    }
}


/**********************************************************************
 * used to direct template espressions through sandbox object
 *********************************************************************/
class TestPrependInterfaceRef extends TemplateUnitTestCase {
    function testBasicPrepend() {
        $template = $this->template;
        $template->sandboxLabel = 'ref';

        $expresison = 'some';
        $prepended = $template->prependInterfaceRef($expresison);
        $this->assertEqual($prepended, '$ref->some');

        $expresison = '1';
        $prepended = $template->prependInterfaceRef($expresison);
        $this->assertEqual($prepended, '1');

        $expresison = 'a ? b : c';
        $prepended = $template->prependInterfaceRef($expresison);
        $this->assertEqual($prepended, '$ref->a ? $ref->b : $ref->c');

        $expresison = '(a&&b) ? b : c';
        $prepended = $template->prependInterfaceRef($expresison);
        $this->assertEqual($prepended, '($ref->a&&$ref->b) ? $ref->b : $ref->c');

        $expresison = 'a||b';
        $prepended = $template->prependInterfaceRef($expresison);
        $this->assertEqual($prepended, '$ref->a||$ref->b');

        $expresison = '(a&&b) ? b : c';
        $prepended = $template->prependInterfaceRef($expresison);
        $this->assertEqual($prepended, '($ref->a&&$ref->b) ? $ref->b : $ref->c');

        $expresison = 'fn_name(123)';
        $prepended = $template->prependInterfaceRef($expresison);
        $this->assertEqual($prepended, '$ref->fn_name(123)');

        $expresison = 'obj->prop';
        $prepended = $template->prependInterfaceRef($expresison);
        $this->assertEqual($prepended, '$ref->obj->prop');

        $expresison = '$a + c';
        $prepended = $template->prependInterfaceRef($expresison);
        $this->assertEqual($prepended, '$ref->a + $ref->c', "Dollar sign input accepted but optional.");

        $expresison = '$obj->prop';
        $prepended = $template->prependInterfaceRef($expresison);
        $this->assertEqual($prepended, '$ref->obj->prop');

        $expresison = '_abc + 123_';
        $prepended = $template->prependInterfaceRef($expresison);
        $this->assertEqual($prepended, '$ref->_abc + 123$ref->_', "Valid labels only - this output will result in syntax error during eval.");
    }
}

/**********************************************************************
 *
 *********************************************************************/
class TestProcessNonStringChunks extends TemplateUnitTestCase {
    function testProcessNonStringChunkBasics() {
        $template = $this->template;

        $expression = 'test';
        $processed = $template->processNonstringChunks($expression, 'strtoupper');
        $this->assertEqual($processed, 'TEST');

        $expression = "one 'two' three";
        $processed = $template->processNonstringChunks($expression, 'strtoupper');
        $this->assertEqual($processed, "ONE 'two' THREE");

        $expression = "one 'two' three";
        $processed = $template->processNonstringChunks($expression, 'str_rot13');
        $this->assertEqual($processed, "bar 'two' guerr");

        $expression = "one 'two' three";
        $callback = create_function('$x', 'return str_replace("o","~",$x);');
        $processed = $template->processNonstringChunks($expression, $callback);
        $this->assertEqual($processed, "~ne 'two' three");

        $expression = "te's\\'t'ing";
        $processed = $template->processNonstringChunks($expression, 'strtoupper');
        $this->assertEqual($processed, "TE's\\'t'ING");

        $expression = "te's\\\"t'ing";
        $processed = $template->processNonstringChunks($expression, 'strtoupper');
        $this->assertEqual($processed, "TE's\\\"t'ING");

        $expression = 'apple "orange" grape';
        $processed = $template->processNonstringChunks($expression, 'strtoupper');
        $this->assertEqual($processed, "APPLE 'orange' GRAPE", 'Double quotes must be converted to single quotes.');

        $expression = 'red . "$green" . BLUE';
        $processed = $template->processNonstringChunks($expression, 'strtoupper');
        $this->assertEqual($processed, "RED . '\$green' . BLUE");

        $expression = "apple 'orange grape' ";
        $processed = $template->processNonstringChunks($expression, 'strtoupper');
        $this->assertEqual($processed, "APPLE 'orange grape' ");

        $expression = "apple 'orange grape'"; // trailing quote test
        $processed = $template->processNonstringChunks($expression, 'strtoupper');
        $this->assertEqual($processed, "APPLE 'orange grape'");

        $expression = "apple 'orange grape"; // unclosed quote
        $processed = $template->processNonstringChunks($expression, 'strtoupper');
        $this->assertEqual($processed, "APPLE 'orange grape");
    }
}

/**********************************************************************
 *
 *********************************************************************/
class Test_getVariableName extends TemplateUnitTestCase {
    function testId() {
        $dom = new DOMDocument();
        $dom->loadXML('<div id="testval">Hello Element</div>');
        $element = $dom->documentElement;

        $name = $this->template->getVariableName($element);
        $this->assertEqual($name, 'testval');
    }
    function testBuiltIn() {
        $dom = new DOMDocument();
        $dom->loadXML('<title>Hello Title</title>');
        $element = $dom->documentElement;

        $name = $this->template->getVariableName($element);
        $this->assertEqual($name, 'title');
    }
    function testNull() {
        $dom = new DOMDocument();
        $dom->loadXML('<div>Hello Title</div>');
        $element = $dom->documentElement;

        $name = $this->template->getVariableName($element);
        $this->assertNull($name, "If no id attribute and not built-in, must be NULL.");
    }
}

/**********************************************************************
 *
 *********************************************************************/
class Test_evalExpression extends TemplateUnitTestCase {
    function testEval() {
        $template = $this->template;
        $dom = new DOMDocument(); // must initialize dom
        $dom->loadHTML('<html><head><title>Hello Title</title></head><body><h1>Hello Body</h1></body></html>');
        $template->contentDom = $dom;

        $expression = '1+2';
        $node = $template->evalExpression($expression);
        $this->assertIsA($node, 'DOMElement');
        $this->assertEqual($node->nodeValue, '3');

        $expression = '12;23|'; // <- mal-formed expression
        $template->debugMode = TRUE;
        $node = $template->evalExpression($expression);
        $this->assertIsA($node, 'DOMElement');
        $this->assertPattern('/syntax error/i', $node->nodeValue);

        /*
        // id and built-in nodes can't be tested with proxy object
        $expression = 'title';
        $node = $template->evalExpression($expression);
        $this->assertIsA($node, 'DOMElement');
        $this->assertEqual($node->tagName, 'title');
        */
    }
}

/**********************************************************************
 *
 *********************************************************************/
class TestPropertyAccess extends TemplateUnitTestCase {
    function testPropertyAccessBasic() {
        $cascade =& new MockTemplarPHP();
        $template = new TemplarTemplateEngine($cascade);
        $template->varNodes['a'] = "value of a"; // TODO: replace with load values and make varNodes protected again
        //echo $template->a;
        //$template->varNodes['a'] = 1;
        //echo 'ASDF';
        //$template->title = 'The Title Value';
        //echo $template->title;
        //$template->varNodes = array("a"=>1, "b"=>2);
        //var_dump($template);
        //echo $template->__get('a');
    }
}


//strtoupper
/*
* TESTS TO ADD:
* renderDom()
* processExpression()
* expressionLexer()
* getVariableName()
* debugMessage()
* removeNode()
* getProcessingInstructions()
*
*
*
*/

/**********************************************************************
 *
 *********************************************************************/
/*
class BlankTestClass extends TemplateUnitTestCase {
    function testNameGoesHere() {
        $value = 2 + 2;
        $this->assertTrue($value == 4);
    }
}
*/


?>
